package top.kaoshanji.p3ch11a;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.Random;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;

/**
 * 代码清单-p3ch11a-356页a：基于AbstractQueuedSynchronizer类的资源管理实现
 * author kaoshanji
 * ^_^
 * create time 2025/2/4 15:28
 */
public class SimpleResourceManager {

    private static final Logger logger = LogManager.getLogger(SimpleResourceManager.class);

    public static void main(String[] args) {
        logger.info("...代码清单-p3ch11a-356页a：基于AbstractQueuedSynchronizer类的资源管理实现...");

        final SimpleResourceManager manager = new SimpleResourceManager(2);
        for (int i = 0; i < 5; i++) {
            new Thread() {

                @Override
                public void run() {
                    try {
                        manager.acquire();
                        String name = Thread.currentThread().getName();
                        System.out.println(name + " ACQUIRE");
                        Random random = new Random();
                        Thread.sleep(random.nextInt(5000));
                        manager.release();
                        System.out.println(name + " RELEASE");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }.start();
        }

        try {
            Thread.sleep(300 * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }


    private final InnerSynchronizer synchronizer;

    private static class InnerSynchronizer extends AbstractQueuedSynchronizer {

        public InnerSynchronizer(int numOfResources) {
            setState(numOfResources);
        }

        @Override
        protected int tryAcquireShared(int acquires) {
            for (;;) {
                int available = getState();
                int remaining = available - acquires;
                if (remaining < 0) {
                    compareAndSetState(available, remaining);
                    return remaining;
                }
            }
        }

        @Override
        protected boolean tryReleaseShared(int releases) {
            for (;;) {
                int available = getState();
                int next = available + releases;
                if (compareAndSetState(available, next)) {
                    return true;
                }
            }
        }
    }

    public SimpleResourceManager(int numOfResources) {
        synchronizer = new InnerSynchronizer(numOfResources);
    }

    public void acquire() throws InterruptedException {
        synchronizer.acquireSharedInterruptibly(1);
    }

    public void release() {
        synchronizer.releaseShared(1);
    }

}
